home *** CD-ROM | disk | FTP | other *** search
Modula Implementation | 1997-05-14 | 14.7 KB | 368 lines | [TEXT/3PRM] |
- implementation module board
-
- import StdEnv
- import language, types
-
- /***************************************************************************************************************
- The dimensions of the board have range of 0..14 to 0..14.
- ****************************************************************************************************************/
-
- :: Board :== (![[Char]],![[Char]])
-
- initboard :: Board
- initboard
- = (emptyboard,emptyboard)
- where
- emptyboard = repeatn 15 (repeatn 15 ' ')
-
- getplacedletters :: !Board -> [Char]
- getplacedletters (h,_)
- = sort (removeDup (flatten h))
-
-
- /***************************************************************************************************************
- The bonus fields on the scrabble board.
- ****************************************************************************************************************/
-
- doubleletterpositions :: [Position]
- doubleletterpositions
- =: [(0,3),(0,11),(2,6),(2,8),(3,7),(3,14),(6,2),(6,6),(6,8),(6,12),(7,3),(7,11),(8,2),(8,6),(8,8),(8,12),(11,7),(11,14),(12,6),(12,8),(14,3),(14,11)]
-
- tripleletterpositions :: [Position]
- tripleletterpositions
- =: [ (1,5),(1,9),(5,1),(5,5),(5,9),(5,13),(9,1),(9,5),(9,9),(9,13),(13,5),(13,9) ]
-
- doublewordpositions :: [Position]
- doublewordpositions
- =: [ (7,7),(1,1),(2,2),(3,3),(4,4),(1,13),(2,12),(3,11),(4,10),(10,4),(10,10),(11,3),(11,11),(12,12),(12,2),(13,13),(13,1) ]
-
- triplewordpositions :: [Position]
- triplewordpositions
- =: [ (0,0),(0,7),(0,14),(7,0),(7,14),(14,0),(14,7),(14,14) ]
-
- lettervalueat :: !Char !Position -> Int
- lettervalueat l pos
- | isMember pos doubleletterpositions = lw*2
- | isMember pos tripleletterpositions = lw*3
- | otherwise = lw
- where
- lw = lettervalue l
-
- wordvalueat :: !Position -> Int
- wordvalueat pos
- | isMember pos doublewordpositions = 2
- | isMember pos triplewordpositions = 3
- | otherwise = 1
-
- grab :: ![Char] !Int [Int] -> (![Char],![Char],[Int])
- grab lb 0 rs = (lb,[],rs)
- grab [] n rs = ([],[],rs)
- grab lb n rs = (restbox,[l:rest],rs2)
- where
- (r,rs1) = random (length lb) rs
- l = lb!!r
- (restbox,rest,rs2) = grab (removeFirst l lb) (n-1) rs1
-
- random :: !Int ![Int] -> (!Int,![Int])
- random i [r:rs] = (r rem i,rs)
-
- removeFirst :: !x ![x] -> [x] | Eq x
- removeFirst x [y:ys]
- | x==y = ys
- | otherwise = [y:removeFirst x ys]
- removeFirst _ _ = []
-
- getfreehorpositions :: !Board !Char -> [Position]
- getfreehorpositions (h,_) l
- = flatten (map (freepositions True l 0) (zip2 [0..] h))
-
- getfreeverpositions :: !Board !Char -> [Position]
- getfreeverpositions (_,v) l
- = map swap (flatten (map (freepositions True l 0) (zip2 [0..] v)))
-
- freepositions :: !Bool !Char !Int !(!Int,![Char]) -> [Position]
- freepositions _ _ _ (_,[])
- = []
- freepositions True k x (y,[l:ls])
- | l==k = [(x,y) : freepositions False k (x+1) (y,ls)]
- | l==' ' = freepositions True k (x+1) (y,ls)
- | otherwise = freepositions False k (x+1) (y,ls)
- freepositions False k x (y,[l:ls])
- | l==' ' = freepositions True k (x+1) (y,ls)
- | otherwise = freepositions False k (x+1) (y,ls)
-
-
- /***************************************************************************************************************
- seekfreepositions is used by seekfree(hor/ver)positions. It determines the positions on a given board that
- are valid starting positions for a word starting with a particular letter.
-
- The function is useful when atleast one letter on the board has to be used because a (some) letter(s) is
- (are) missing on the letter bar.
- ****************************************************************************************************************/
- seekfreehorpositions :: !Board !Char !Int -> [Position]
- seekfreehorpositions (h,v) k p
- = flatten (map (seekfreepositions 0 p k 0) (zip2 [0..] h))
-
- swap :: !(.a,.b) -> (.b,.a)
- swap (a,b) = (b,a)
-
- seekfreeverpositions :: !Board !Char !Int -> [Position]
- seekfreeverpositions (h,v) k p
- = map swap (flatten (map (seekfreepositions 0 p k 0) (zip2 [0..] v) ))
-
- seekfreepositions :: !Int !Int !Char !Int !(!Int,![Char]) -> [Position]
- seekfreepositions a p k x (y,[l:ls])
- | a>=p && k==l = [(x-p,y) : seekfreepositions 0 p k (x+1) (y,ls)]
- | l==' ' = seekfreepositions (a+1) p k (x+1) (y,ls)
- | otherwise = seekfreepositions 0 p k (x+1) (y,ls)
- seekfreepositions _ _ _ _ _
- = []
-
-
- /***************************************************************************************************************
- tryaddword board word position direction adds word at position in direction to board.
- The Board result is the new board.
- The Boolean result reports whether the word could be placed.
- The [Char] result are the letters that have been used.
- The Int result is the score by placing this word.
- The [Word] result are the possibly new formed words.
-
- After tryaddword it should be verified if the new formed words are legal.
- After tryaddword it also should be verified if a bonus should be added to the score in case all letters
- have been used.
- ****************************************************************************************************************/
- tryaddword :: !Board !Word !Position !Direction -> (!Board,!Bool,[Char],Int,[Word])
- tryaddword board=:(h,v) w (x,y) Hor
- | w=="" = (board,True, [],0,[])
- | size w + x > 15 = (board,False,[],0,[])
- | otherwise = ((nh,nv),possible,newletters,score,newwords)
- where
- (nh,possible,scorenewletters,worddoubling)
- = tryaddtolines h w (x,y) y
- (nv,vscore,newwords)= tryaddtransversetolines v (0,y) scorenewletters
- newletters = map fst3 scorenewletters
- scoreoldletters = oldletterscore w newletters
- hscore = worddoubling*(sum (map thd3 scorenewletters) + scoreoldletters)
- score
- | not possible = 0
- | otherwise = hscore+vscore
- tryaddword board=:(h,v) w (x,y) Ver
- | w=="" = (board,True, [],0,[])
- | size w + y > 15 = (board,False,[],0,[])
- | otherwise = ((nh,nv),possible,newletters,vscore+hscore,newwords)
- where
- (nv,possible,scorenewletters,worddoubling)
- = tryaddtolines v w (y,x) x
- (nh,hscore,newwords)= tryaddtransversetolines h (0,x) scorenewletters
- newletters = map fst3 scorenewletters
- scoreoldletters = oldletterscore w newletters
- vscore = worddoubling*(sum (map thd3 scorenewletters) + scoreoldletters)
-
- oldletterscore :: !Word ![Char] -> Int // Sum the lettervalue of the chars in word that are not member of letters
- oldletterscore word letters
- = sum (map lettervalue (removeMembers [c\\c<-:word] letters))
-
- tryaddtolines :: ![[Char]] Word !Position !Int -> (![[Char]],!Bool,![(Char,Int,Int)],Int)
- tryaddtolines [r:rs] w p=:(x,_) 0
- # (r,possible,scorenewletters,worddoubling) = tryaddtoline r w p x
- = ([r:rs],possible,scorenewletters,worddoubling)
- where
- tryaddtoline :: ![Char] !Word !Position !Int -> (![Char],!Bool,![(Char,Int,Int)],Int)
- tryaddtoline rs word p 0
- | nrchars==1 = addtoline
- with
- addtoline
- | l==' ' && (ls==[] || hd ls==' ') = ([w:ls],True, [lwrd],wwrd)
- | l==w && (ls==[] || hd ls==' ') = ([w:ls],True, [],1)
- | otherwise = ([l:ls],False,[],1)
- | nrchars>=1 = addtoline
- with
- (nr,possible,lwrds,wwrds) = tryaddtoline ls (word%(1,nrchars-1)) (x+1,y) 0
- addtoline
- | l==' ' = ([w:nr],possible,[lwrd:lwrds],wwrd*wwrds)
- | l==w = ([w:nr],possible,lwrds,wwrds)
- | otherwise = ([l:ls],False,[],1)
- where
- nrchars = size word
- (l,ls) = hdtl rs
- w = word.[0]
- (x,y) = p
- wvalue = lettervalueat w p
- lwrd = (w,x,wvalue)
- wwrd = wordvalueat p
- tryaddtoline rs word p 1
- | l<>' ' = (rs,False,[],1)
- # (ls,possible,lwrds,wwrds) = tryaddtoline ls word p 0
- | otherwise = ([l:ls],possible,lwrds,wwrds)
- where
- (l,ls) = hdtl rs
- tryaddtoline [l:ls] word p n
- # (ls,possible,lwrds,wwrds) = tryaddtoline ls word p (n-1)
- = ([l:ls],possible,lwrds,wwrds)
-
- hdtl :: ![.x] -> (.x,[.x])
- hdtl [x:xs] = (x,xs)
- tryaddtolines [r:rs] w p j
- # (rs,possible,scorenewletters,worddoubling) = tryaddtolines rs w p (j-1)
- = ([r:rs],possible,scorenewletters,worddoubling)
- tryaddtolines _ _ _ _
- = ([],False,[],0)
-
- tryaddtransversetolines :: ![[Char]] !Position ![(Char,Int,Int)] -> (![[Char]],Int,![Word])
- tryaddtransversetolines rs _ []
- = (rs,0,[])
- tryaddtransversetolines [r:rs] p=:(x,y) [(nl,nx,ls)]
- | x==nx = ([nr:rs],score,newword)
- with
- (nr,score,newword) = addtoline r nl p y ""
- | otherwise = ([r:nrs],score,newword)
- with
- (nrs,score,newword) = tryaddtransversetolines rs (x+1,y) [(nl,nx,ls)]
- tryaddtransversetolines [r:rs] p=:(x,y) [(nl,nx,ls):lwrds]
- | x==nx = ([nr:nrs],score+restscore,newword++newwords)
- with
- (nrs,restscore,newwords)= tryaddtransversetolines rs (x+1,y) lwrds
- (nr,score,newword) = addtoline r nl p y ""
- | otherwise = ([r:nrs],restscore,newwords)
- with
- (nrs,restscore,newwords)= tryaddtransversetolines rs (x+1,y) [(nl,nx,ls):lwrds]
- tryaddtransversetolines [r:rs] (x,y) lwrds
- = ([r:nrs],score,newwords)
- where
- (nrs,score,newwords) = tryaddtransversetolines rs (x-1,y) lwrds
-
- addtoline :: ![Char] !Char Position !Int !Word -> (![Char],Int,![Word])
- addtoline [l:ls] w p 0 initword
- | initwordscore+restwordscore<>0 = ([w:ls],(initwordscore+lscore+restwordscore)*wscore,[word])
- | otherwise = ([w:ls],0,[])
- where
- lscore = lettervalueat w p
- wscore = wordvalueat p
- restword = takeWhile ((<>) ' ') ls
- initwordscore = sum [lettervalue c \\ c<-:initword]
- restwordscore = sum (map lettervalue restword)
- word = initword +++ toString w +++ toString restword
- addtoline [l:ls] w p ry initword
- # initword = if (l<>' ') (initword+++toString l) ""
- (ls,score,word) = addtoline ls w p (ry-1) initword
- = ([l:ls],score,word)
-
-
- /***************************************************************************************************************
- newmaximumplacings _ lexicon letterbar _ (Letter l _) _ _ determines all valid words from lexicon that
- start with l and are member of letterbar.
- ****************************************************************************************************************/
- newmaximumplacings :: !Board Tree [Char] !(!Int,!Int,!Int,!Int) !Progress !Strength Bool -> Placing
- newmaximumplacings board wordlist computerletters (minx,maxx,miny,maxy) progress=:(Letter l placing) strength firstturn
- = scoremax strength [placing:newfoundplacings1++newfoundplacings2]
- where
- startwith = wordsstartingwith l wordlist
- uniquecomputerletters = removeDup computerletters
- poshor = getfreehorpositions board l
- posver = getfreeverpositions board l
- newfoundplacings1
- = [ {word=nw,pos=p,dir=r,/*endscore*/score=if (length gl==7) (s+50) s}
- \\ nw <- startwith
- , (firstmissingletter,position) <- [difference nw uniquecomputerletters 0]
- , r <- [Hor,Ver]
- , p <- if (position<>7) (if (r==Hor)
- (seekfreehorpositions board firstmissingletter position)
- (seekfreeverpositions board firstmissingletter position)
- )
- (if (r==Hor)
- [(i,j) \\ i <- [max 0 (minx-size nw) .. min (14-size nw) maxx]
- , j <- [max 0 (miny-1) .. min 14 (maxy+1)]]
- [(i,j) \\ i <- [max 0 (minx-1) .. min 14 (maxx+1)]
- , j <- [max 0 (miny-size nw) .. min (14-size nw) maxy]]
- )
- , (_,m,gl,s,nws) <- [tryaddword board nw p r]
- | ok_solution m gl nws nw
- ]
- ok_solution m gl nws nw
- = m &&
- (not (isEmpty gl)) &&
- isEmpty (removeMembers gl computerletters) &&
- ((not (isEmpty nws)) || length gl<>size nw || firstturn) &&
- allexist wordlist nws
- newfoundplacings2
- = addatpositions board wordlist computerletters (poshor,posver) progress firstturn
-
- // difference word letterbar determines which letter and its position in word that is not a member of letterbar.
- difference :: !Word ![Char] !Int -> (!Char,!Int)
- difference word letters p
- | word=="" = ('a',7)
- # l = word.[0]
- word = word%(1,size word-1)
- | isMember l letters = difference word letters (p+1)
- | otherwise = (l,p)
-
-
- /***************************************************************************************************************
- newmaximumplacing board lexicon letterbar (hor,ver) (Letter l _) _ _ determines all valid words from lexicon
- that start with l and are not member of letterbar. The positions hor++ver are assumed to be valid free
- positions on board starting with l.
- ****************************************************************************************************************/
- newmaximumplacing :: !Board Tree [Char] ([Position],[Position]) !Progress !Strength Bool -> Placing
- newmaximumplacing board wordlist computerletters poshv progress=:(Letter l placing) strength firstturn
- = scoremax strength [placing:addatpositions board wordlist computerletters poshv progress firstturn]
- newmaximumplacing _ _ _ _ (Finish ready) _ _
- = ready
-
- addatpositions :: !Board Tree [Char] !([Position],[Position]) !Progress Bool -> [Placing]
- addatpositions board wordlist computerletters (poshor,posver) (Letter l _) firstturn
- = [ {word=nw,pos=p,dir=r,/*endscore*/score=if (length gl==7) (s+50) s}
- \\ nw<- startwith
- | wordcontainsletters nw uniquecomputerletters
- , r <- [Hor,Ver]
- , p <- if (r==Hor) poshor posver
- , (_,m,gl,s,nws) <- [tryaddword board nw p r]
- | ok_solution m gl nws nw
- ]
- where
- ok_solution m gl nws nw
- = m &&
- not (isEmpty gl) &&
- isEmpty (removeMembers gl computerletters) &&
- (not (isEmpty nws) || length gl<>size nw || firstturn) &&
- allexist wordlist nws
- startwith = wordsstartingwith l wordlist
- uniquecomputerletters = removeDup computerletters
-
- wordcontainsletters :: !Word [Char] -> Bool
- wordcontainsletters word letters
- | word=="" = False
- | isMember word.[0] letters = True
- | otherwise = wordcontainsletters (word%(1,size word-1)) letters
-
-
- /***************************************************************************************************************
- scoremax selects a Placing depending on the Strength of the player.
- ****************************************************************************************************************/
- scoremax :: !Strength ![Placing] -> Placing
- scoremax First ps
- # ps = dropWhile ((==) initplacing) ps
- | isEmpty ps = initplacing
- | otherwise = hd ps
- scoremax Maximum ps
- = getmaxscore ps
- where
- getmaxscore :: ![Placing] -> Placing
- getmaxscore [p] = p
- getmaxscore [p1:ps]
- | p1.score>p2.score = p1
- | otherwise = p2
- where
- p2 = getmaxscore ps
- getmaxscore [] = initplacing
- scoremax (Strength percent) ps
- = scoremax Maximum (take nr ps)
- where
- nr = toInt (toReal (length ps)*percent) + 1
-
-
- /***************************************************************************************************************
- allexists is true only if each of the words in the [Word] argument can be found in the Tree argument.
- ****************************************************************************************************************/
- allexist :: Tree ![Word] -> Bool
- allexist wordlist words = and (map (seek wordlist) words)
-